#include "xtypes.h"
#include "util_thread.h"
#include"xmemory.h"
#include"util_sync.h"

#ifndef _WIN32_WINNT		
#define _WIN32_WINNT 0x0501
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <process.h>

bool_t CxThread::IsRunning()
{
	return m_ThreadStatus==XTHREAD_STATUS_RUN ? TRUE:FALSE;
}

xResult CxThread::Run()
{
	if( m_ThreadStatus!=XTHREAD_STATUS_STOP )
		return XR_FAIL;
	if(_ThreadProc==NULL)
		return XR_FAIL;

	XTHREAD_PROTECT_DAEMON;

	m_ThreadHandle = _beginthreadex( NULL, m_nStackSize, _ThreadProc, (void*)this, 0, &m_ThreadId);

	return m_ThreadHandle!=0 ? XR_OK:XR_FAIL;
}

xResult CxThread::Terminate( uint_t _Retval )
{
	if( m_ThreadStatus==XTHREAD_STATUS_STOP || m_ThreadStatus==XTHREAD_STATUS_INVALID )
		return XR_FAIL;

	XTHREAD_PROTECT_DAEMON;

	BOOL ret = ::TerminateThread((HANDLE)m_ThreadHandle, _Retval );

	if(ret==TRUE)
	{
		m_ThreadHandle = XTHREAD_STATUS_STOP;
		m_ThreadHandle = 0;
		m_ThreadId = 0;
		return XR_OK;
	}
	else
	{
		return XR_FAIL;
	}
}

bool_t CxThread::IsSuspended()
{
	return m_ThreadStatus==XTHREAD_STATUS_SUSPEND ? TRUE:FALSE;
}


xResult CxThread::Suspend()
{
	if(m_ThreadStatus!=XTHREAD_STATUS_RUN)
		return XR_FAIL;

	XTHREAD_PROTECT_DAEMON;

	DWORD nRet = ::SuspendThread((HANDLE)m_ThreadHandle);
	if(nRet!=0xFFFFFFFF)
	{
		m_ThreadStatus = XTHREAD_STATUS_SUSPEND;
		return XR_OK;
	}
	else
	{
		return XR_FAIL;
	}
}

xResult CxThread::Resume()
{
	if(m_ThreadStatus!=XTHREAD_STATUS_SUSPEND)
		return XR_FAIL;

	XTHREAD_PROTECT_DAEMON;

	DWORD nRet = ::ResumeThread((HANDLE)m_ThreadHandle);
	if(nRet!=0xFFFFFFFF)
	{
		m_ThreadStatus = XTHREAD_STATUS_RUN;
		return XR_OK;
	}
	else
	{
		return XR_FAIL;
	}
}

void CxThread::SetThreadAddr( t_xThreadAddress _pThreadAddr )
{
	m_pThreadAddr = _pThreadAddr;
}

void CxThread::SetArgList( wildptr_t _pArgList )
{
	m_pArgList = _pArgList;
}

void CxThread::SetBeginEventFunc( t_xThreadEventFuncAddress _pOnThreadBegin )
{
	m_pOnThreadBegin = _pOnThreadBegin;
}

void CxThread::SetEndEventFunc( t_xThreadEventFuncAddress _pOnThreadEnd )
{
	m_pOnThreadEnd = _pOnThreadEnd;
}

void CxThread::SetStackSize( int_t _StackSize )
{
	m_nStackSize = _StackSize;
}

wildptr_t CxThread::GetArgList()
{
	return m_pArgList;
}

int_t CxThread::GetThreadStatus()
{
	return m_ThreadStatus;
}

int_t CxThread::GetStackSize()
{
	return m_nStackSize;
}

uint_t CxThread::GetThreadHandle()
{
	return m_ThreadHandle;
}

uint_t CxThread::GetThreadId()
{
	return m_ThreadId;
}

CxThread::CxThread()
{
	_Init();
	_Alloc();
}

CxThread::~CxThread()
{
	_Tidy();
}

CxThread * CxThread::Create( t_xThreadAddress _ThreadAddr /*= NULL*/, wildptr_t _ArgList /*= NULL*/, t_xThreadEventFuncAddress _BeginEvent /*= NULL*/, t_xThreadEventFuncAddress _EndEvent /*= NULL */ )
{
	CxThread * _Ptr = xNewObject<CxThread>();
	if(_Ptr==NULL)
		return NULL;

	_Ptr->m_pThreadAddr = _ThreadAddr;
	_Ptr->m_pArgList = _ArgList;
	_Ptr->m_pOnThreadBegin = _BeginEvent;
	_Ptr->m_pOnThreadEnd = _EndEvent;
	return _Ptr;
}

void CxThread::Release()
{
	xDeleteObject<CxThread>(this);
}

void CxThread::_Init()
{
	m_nStackSize = 0;
	m_ThreadStatus = XTHREAD_STATUS_INVALID;
	m_pThreadAddr = NULL;
	m_pArgList = NULL;
	m_ThreadHandle = 0;
	m_ThreadId = 0;
	m_pOnThreadBegin = NULL;
	m_pOnThreadEnd = NULL;
}

void CxThread::_Alloc()
{
	_Tidy();
	m_ThreadStatus = XTHREAD_STATUS_STOP;
}

void CxThread::_Tidy()
{
	if(m_ThreadStatus==XTHREAD_STATUS_RUN || m_ThreadStatus==XTHREAD_STATUS_SUSPEND)
	{
		this->Terminate(-1);
	}
	m_ThreadHandle = 0;
	m_ThreadId = 0;
	m_ThreadStatus = XTHREAD_STATUS_INVALID;
}


uint_t CxThread::ThreadProc()
{
	uint_t nRet = -1;
	if(m_pThreadAddr!=NULL)
	{
		nRet = (m_pThreadAddr)(m_pArgList);
	}
	return nRet;
}

uint_t __STDCALL CxThread::_ThreadProc( void * _Arg )
{
	uint_t nRet = -1;
	CxThread * pThis = (CxThread *)_Arg;

	pThis->m_ThreadStatus = XTHREAD_STATUS_RUN;
	pThis->_OnThreadBegin();
	nRet = pThis->ThreadProc();
	pThis->_OnThreadEnd();
	pThis->m_ThreadStatus = XTHREAD_STATUS_STOP;
	pThis->m_ThreadHandle = 0;
	pThis->m_ThreadId = 0;

	return nRet;
}

void CxThread::_OnThreadBegin()
{
	if(m_pOnThreadBegin!=NULL)
	{
		(*m_pOnThreadBegin)();
	}
}

void CxThread::_OnThreadEnd()
{
	if(m_pOnThreadBegin!=NULL)
	{
		(*m_pOnThreadEnd)();
	}
}





void xExitThread( uint_t _Retval )
{
	_endthreadex(_Retval);
}


void xSleepThread(ulong_t _Ms)
{
	Sleep(_Ms);
}